Go 专家编程是一本比较通熟易懂的 Go 进阶书籍,早豆瓣评分也很高,学习比较整理如下,源码: https://github.com/rexyan/go_zjbc
Slice 切片 创建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 package mainimport "fmt" func main () { var s []int s1 := []int {} s2 := []int {1 , 2 , 3 } fmt.Println(s, s1, s2) s3 := make ([]int , 10 ) s4 := make ([]int , 10 , 100 ) fmt.Println(s3, s4) array := [5 ]int {1 , 2 , 3 , 4 , 5 } s5 := array[0 :2 ] s6 := s5[0 :1 ] fmt.Println(s5, s6) }
追加操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package mainimport "fmt" func main () { s7 := make ([]int , 0 ) s7 = append (s7, 1 ) s7 = append (s7, 2 , 3 , 4 , 5 , 6 ) s7 = append (s7, []int {7 , 8 , 9 }...) fmt.Println(s7) }
实现原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package mainimport "fmt" func main () { array := [10 ]int {} slice := array[5 :7 ] fmt.Println(len (slice), cap (slice)) }
扩容 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package mainimport "fmt" func main () { slice := make ([]int , 5 , 5 ) fmt.Println(len (slice), cap (slice)) slice = append (slice, 1 ) fmt.Println(len (slice), cap (slice)) }
切片表达式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package mainimport "fmt" func main () { baseArray := [10 ]int {} newSlice1 := baseArray[0 :10 ] fmt.Println(newSlice1, len (newSlice1), cap (newSlice1)) baseSlice := make ([]int , 0 , 10 ) newSlice2 := baseSlice[2 :5 ] fmt.Println(newSlice2, len (newSlice2), cap (newSlice2)) array := [10 ]int {} slice := array[5 :7 :7 ] fmt.Println(slice, len (slice), cap (slice)) }
String 字符串 注意事项 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package mainimport "fmt" func main () { s := "中国" for index, value := range s { fmt.Println(index, value) } }
Map 注意事项 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package mainimport "fmt" func main () { var exampleMap map [string ]int fmt.Println(exampleMap["key" ]) value, exist := exampleMap["key" ] if exist { fmt.Println(value) } delete (exampleMap, "key1" ) }
实现原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package mainfunc main () { }
iota 取值规则 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 package mainimport "fmt" func main () { fmt.Println(LOG_EMERG) fmt.Println(LOG_ALERT) fmt.Println(LOG_CRIT) fmt.Println(LOG_ERR) fmt.Println(LOG_WARNING) fmt.Println(LOG_NOTICE) fmt.Println(LOG_INFO) fmt.Println(LOG_DEBUG) fmt.Println(bit0, mask0) fmt.Println(bit1, mask1) fmt.Println(bit3, mask3) fmt.Println(mutexLocked) fmt.Println(mutexWoken) fmt.Println(mutexStarving) fmt.Println(mutexWaiterShift) fmt.Println(starvationThresholdNs) } type Priority int const ( LOG_EMERG Priority = iota LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG ) const ( bit0, mask0 = 1 << iota , 1 <<iota - 1 bit1, mask1 _, _ bit3, mask3 ) const ( mutexLocked = 1 << iota mutexWoken mutexStarving mutexWaiterShift = iota starvationThresholdNs = 1e6 )
Struct 结构体 获取 tag 信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package mainimport ( "encoding/json" "fmt" "reflect" ) type TypeMeta struct { Kind string `json:"kind,omitempty"` ApiVersion string `json:"apiVersion,omitempty"` } func main () { t := TypeMeta{ Kind: "kind" , } ty := reflect.TypeOf(t) for i := 0 ; i < ty.NumField(); i++ { fmt.Printf("字段名称:%s, Json Tag:%s\n" , ty.Field(i).Name, ty.Field(i).Tag.Get("json" )) } marshal, err := json.Marshal(t) if err != nil { return } fmt.Println(marshal) }
Channel 通道 创建,以及触发nil情况 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package mainimport ( "fmt" ) func main () { var ch chan int ch = make (chan int , 8 ) ch1 := make (chan string ) ch2 := make (chan string , 5 ) fmt.Println(ch) fmt.Println(ch1) fmt.Println(ch2) }
单向管道 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package mainfunc readChan (chanName <-chan int ) { <-chanName } func writeChan (chanName chan <- int ) { chanName <- 1 } func main () { myChan := make (chan int , 10 ) writeChan(myChan) readChan(myChan) }
select 和管道 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package mainimport ( "fmt" "time" ) func addNumberToChan (chanName chan int ) { for { chanName <- 1 time.Sleep(time.Second * 1 ) } } func main () { var chan1 = make (chan int , 10 ) var chan2 = make (chan int , 10 ) go addNumberToChan(chan1) go addNumberToChan(chan2) for { select { case e := <-chan1: fmt.Printf("从 chan1 接受到数据%d\n" , e) case e := <-chan2: fmt.Printf("从 chan2 接受到数据%d\n" , e) default : fmt.Printf("未接收到数据\n" ) time.Sleep(time.Second * 1 ) } } }
for-range 和管道 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package mainimport ( "fmt" "time" ) func addDataToChan (chanName chan int ) { for { chanName <- 1 time.Sleep(time.Second * 1 ) } } func main () { var chan1 = make (chan int , 10 ) go addDataToChan(chan1) for e := range chan1 { fmt.Printf("从 chan2 接受到数据%d\n" , e) } }
Select 特性 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 package mainimport "fmt" func main () { } func SelectForChan (c chan string ) { var recv string send := "hello" select { case recv = <-c: fmt.Printf("从管道接收到了数据%s\n" , recv) case c <- send: fmt.Printf("将数据%s送入了管道\n" , send) } }
管道返回值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 package mainimport "fmt" func main () { c := make (chan string ) close (c) SelectAssign(c) } func SelectAssign (c chan string ) { select { case <-c: fmt.Println("不接收返回值" ) case d := <-c: fmt.Printf("接收一个返回值 %s" , d) case d, ok := <-c: if !ok { fmt.Println("管道已经关闭" ) break } fmt.Printf("接收两个返回值 %s" , d) } }
default 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package mainimport "fmt" func main () { c := make (chan string ) select { default : fmt.Println("default" ) case <-c: fmt.Println("读取数据" ) } }
使用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 package mainimport ( "fmt" "time" ) func main () { stopCh := make (chan struct {}) go func () { doSomething() stopCh <- struct {}{} }() stopWithTimeOut := waitForStopOrTimeOut(stopCh, 3 *time.Second) select { case isTimeOut := <-stopWithTimeOut: if isTimeOut { fmt.Println("end timeout" ) } else { fmt.Println("end ok" ) } } } func waitForStopOrTimeOut (stopCh <-chan struct {}, timeout time.Duration) <-chan bool { stopWithTimeOut := make (chan bool ) go func () { select { case <-stopCh: fmt.Println("自然结束" ) stopWithTimeOut <- false case <-time.After(timeout): fmt.Println("超时" ) stopWithTimeOut <- true } close (stopWithTimeOut) }() return stopWithTimeOut } func doSomething () { time.Sleep(time.Second * 5 ) }
并发 channel 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package mainimport ( "fmt" "time" ) func Process (ch chan int ) { time.Sleep(time.Second * 2 ) ch <- 1 } func main () { channels := make ([]chan int , 10 ) for i := 0 ; i < 10 ; i++ { channels[i] = make (chan int ) go Process(channels[i]) } for i, ch := range channels { <-ch fmt.Printf("channel %d end!\n" , i) } }
WaitGroup 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package mainimport ( "fmt" "sync" "time" ) func main () { var wg sync.WaitGroup wg.Add(2 ) go func () { time.Sleep(time.Second * 3 ) fmt.Println("goroutine 1 end!" ) wg.Done() }() go func () { time.Sleep(time.Second * 1 ) fmt.Println("goroutine 2 end!" ) wg.Done() }() wg.Wait() fmt.Println("all goroutine finished!" ) }
context 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package mainfunc main () { }
cancelCtx 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 package mainimport ( "context" "fmt" "time" ) func HandelRequest (ctx context.Context) { go WriteRedis(ctx) go WriteDB(ctx) for { select { case <-ctx.Done(): fmt.Println("HandelRequest Done!" ) return default : fmt.Println("HandelRequest Running!" ) time.Sleep(time.Second * 1 ) } } } func WriteDB (ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("WriteDB Done!" ) return default : fmt.Println("WriteDB Running!" ) time.Sleep(time.Second * 5 ) } } } func WriteRedis (ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("WriteRedis Done!" ) return default : fmt.Println("WriteRedis Running!" ) time.Sleep(time.Second * 3 ) } } } func main () { ctx, cancel := context.WithCancel(context.Background()) go HandelRequest(ctx) time.Sleep(time.Second * 10 ) cancel() time.Sleep(time.Second * 3 ) }
timerCtx 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 package mainimport ( "context" "fmt" "time" ) func HandelRequest (ctx context.Context) { go WriteRedis(ctx) go WriteDB(ctx) for { select { case <-ctx.Done(): fmt.Println("HandelRequest Done!" ) return default : fmt.Println("HandelRequest Running!" ) time.Sleep(time.Second * 1 ) } } } func WriteDB (ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("WriteDB Done!" ) return default : fmt.Println("WriteDB Running!" ) time.Sleep(time.Second * 5 ) } } } func WriteRedis (ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("WriteRedis Done!" ) return default : fmt.Println("WriteRedis Running!" ) time.Sleep(time.Second * 3 ) } } } func main () { ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(time.Second*10 )) go HandelRequest(ctx) time.Sleep(time.Second * 15 ) }
valueCtx 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 package mainimport ( "context" "fmt" "time" ) func main () { timeoutCtx, _ := context.WithTimeout(context.Background(), time.Second*3 ) valueCtx := context.WithValue(timeoutCtx, "param" , "rex" ) go HandelRequest(valueCtx) time.Sleep(time.Second * 5 ) } func HandelRequest (ctx context.Context) { for { select { case <-ctx.Done(): fmt.Println("HandelRequest Done!" ) return default : fmt.Println("HandelRequest Running! Get Context Param value: " , ctx.Value("param" )) time.Sleep(time.Second * 1 ) } } }
反射 比较两个结构体变量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package mainimport ( "fmt" "reflect" ) type Foo struct { A int B string C interface {} } func main () { f1 := Foo{ A: 1 , B: "1" , C: []int {1 , 2 , 3 }, } f2 := Foo{ A: 1 , B: "1" , C: []int {1 , 2 , 3 }, } fmt.Println(IsEqual(f1.C, f2.C)) } func IsEqual (a, b interface {}) bool { return reflect.DeepEqual(a, b) }
反射定律 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package mainimport ( "fmt" "reflect" ) func main () { var x float64 = 3.4 t := reflect.TypeOf(x) fmt.Println("type: " , t) v := reflect.ValueOf(x) fmt.Println("value: " , v) var A interface {} A = 100 z := reflect.ValueOf(A) B := z.Interface() fmt.Println(A == B) var k float64 = 54 i := reflect.ValueOf(&k) i.Elem().SetFloat(89.1 ) fmt.Println(k) fmt.Println(i.Elem().Interface()) }
逃逸分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 package mainimport "fmt" func main () { RegisterStudent("rex" , 18 ) Slice() Demo() f := Fibonacci() for i := 0 ; i < 10 ; i++ { fmt.Printf("%d\n" , f()) } } type Student struct { Name string Age int } func RegisterStudent (name string , age int ) *Student { s := new (Student) s.Age = age s.Name = name return s } func Slice () { s := make ([]int , 10000 , 10000 ) for index, _ := range s { s[index] = index } } func Demo () { s := "demo" fmt.Println(s) } func Fibonacci () func () int { a, b := 0 , 1 return func () int { a, b = b, a+b return a } }
timer & ticker 一次性定时器 Timer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package mainimport ( "fmt" "time" ) func main () { ch := make (chan string , 1 ) WaitChannel(ch) time.Sleep(time.Second * 2 ) DelayFunc() } func WaitChannel (ch <-chan string ) bool { timer := time.NewTimer(time.Second * 1 ) select { case <-ch: timer.Stop() return true case <-timer.C: fmt.Println("WaitChannel timeout!" ) return false } } func DelayFunc () { timer := time.NewTimer(time.Second * 3 ) select { case <-timer.C: fmt.Println("延迟执行方法" ) } }
Timer 对外暴露的接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package mainimport ( "fmt" "time" ) func main () { timer := time.NewTimer(time.Second * 5 ) fmt.Println(timer) timer.Stop() timer.Reset(time.Second * 5 ) }
简单接口创建 Timer 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 package mainimport ( "log" "time" ) func main () { log.Println(time.Now()) time.After(time.Second * 2 ) log.Println(time.Now()) log.Println(time.Now()) time.AfterFunc(time.Second*2 , func () { log.Println("AfterFunc End!" , time.Now()) }) time.Sleep(time.Second * 3 ) }
Timer 实现原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 package mainfunc main () { }
周期性定时器 Ticker 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package mainimport ( "fmt" "time" ) func main () { ticker := time.NewTicker(time.Second * 2 ) defer ticker.Stop() count := 0 for range ticker.C { fmt.Println("2s 一次" ) count += 1 if count >= 5 { break } } }
Ticker 实现原理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 package mainfunc main () { }
defer 使用场景 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package mainfunc main () { }
行为规则 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 package mainfunc main () { }
panic 注意事项 1 2 3 4 5 6 7 8 9 10 package mainfunc main () { }
使用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 package mainimport ( "fmt" "time" ) func main () { } func PanicDemo1 () { defer func () { recover () }() foo1() } func foo1 () { defer fmt.Println("A" ) defer fmt.Println("B" ) fmt.Println("C" ) panic ("demo" ) defer fmt.Println("D" ) } func PanicDemo2 () { defer func () { recover () }() defer func () { fmt.Println("1" ) }() foo2() } func foo2 () { defer fmt.Println("A" ) defer fmt.Println("B" ) fmt.Println("C" ) panic ("demo" ) defer fmt.Println("D" ) } func PanicDemo3 () { defer func () { fmt.Println("demo" ) }() go foo3() time.Sleep(time.Second * 1 ) } func foo3 () { defer fmt.Println("A" ) defer fmt.Println("B" ) fmt.Println("C" ) panic ("demo" ) defer fmt.Println("D" ) } func PanicDemo4 () { defer func () { recover () }() defer fmt.Println("A" ) defer func () { fmt.Println("B" ) panic ("panic in defer" ) fmt.Println("C" ) }() panic ("panic" ) fmt.Println("D" ) }
recover 注意事项 1 2 3 4 5 6 7 8 9 10 package mainfunc main () { }
使用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 package mainimport "fmt" func main () { } func RecoverDemo1 () { defer func () { if err := recover (); err != nil { fmt.Println("A" ) } }() panic ("demo" ) fmt.Println("B" ) } func RecoverDemo2 () { defer func () { func () { if err := recover (); err != nil { fmt.Println("A" ) } }() }() panic ("demo" ) fmt.Println("B" ) } func RecoverDemo3 () { defer func () { fmt.Println("C" ) }() defer func () { if err := recover (); err != nil { fmt.Println("A" ) } }() panic ("demo" ) fmt.Println("B" ) } func RecoverDemo4 () { defer func () { if err := recover (); err != nil { fmt.Println("A" ) } }() defer func () { if err := recover (); err != nil { fmt.Println("B" ) } }() panic ("demo" ) fmt.Println("C" ) } func RecoverDemo5 () { foo := func () int { defer func () { recover () }() panic ("demo" ) return 10 } ret := foo() fmt.Println(ret) }
异常处理 error 的创建 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package mainimport ( "errors" "fmt" ) func main () { errors.New("new error" ) fmt.Errorf("file not found, file name: %s" , "1.txt" ) }
检查 error 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package mainimport ( "errors" "fmt" "os" ) func main () { err := errors.New("test error" ) if err != nil { fmt.Println("error" ) } ErrPermission := errors.New("permission denied" ) if err == ErrPermission { fmt.Println("permission error" ) } if e, ok := err.(*os.PathError); ok { fmt.Printf("PathError, operation: %s, path: %s. msg :%v" , e.Op, e.Path, e.Err) } }
传递 error 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 package mainimport ( "errors" "fmt" ) func main () { err := errors.New("this is demo error" ) err2 := fmt.Errorf("same context: %v" , err) if _, ok := err2.(interface { Unwrap() error }); !ok { fmt.Println("未实现 Unwrap() 接口" ) } err3 := fmt.Errorf("same context: %w" , err) if _, ok := err3.(interface { Unwrap() error }); ok { fmt.Println("实现了 Unwrap() 接口" ) } }
链式 error 使用注意事项 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 package mainimport ( "errors" "fmt" ) func main () { err := errors.New("demo error" ) fmt.Errorf("permission error %w, %w" , err, err) fmt.Errorf("permission error %w" , "this is text content" ) }
Unwrap Is As 的用法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 package mainimport ( "errors" "fmt" "os" ) func main () { err := fmt.Errorf("write file error: %w" , os.ErrPermission) if errors.Unwrap(err) == os.ErrPermission { fmt.Println("Permission denied" ) } err2 := fmt.Errorf("write file error: %w" , os.ErrPermission) err3 := fmt.Errorf("write file error: %w" , err2) if errors.Is(err3, os.ErrPermission) { fmt.Println("Permission denied" ) } err4 := &os.PathError{ Op: "write" , Path: "/root/xxx" , Err: os.ErrPermission, } err5 := fmt.Errorf("some context: %w" , err4) var target *os.PathError if errors.As(err5, &target) { fmt.Println("PathError" ) } }
测试 单元测试 1 2 3 4 5 6 7 8 9 10 11 12 package testfunc Add (a int , b int ) int { return a + b }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 package testimport "testing" func TestAdd (t *testing.T) { var a = 1 var b = 2 var c = 3 r := Add(a, b) if c != r { t.Error("test Add fail" ) } }
性能测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package testfunc MakeSliceWithoutAlloc () []int { var newSlice []int for i := 0 ; i < 100000 ; i++ { newSlice = append (newSlice, i) } return newSlice } func MakeSliceWithAlloc () []int { var newSlice []int newSlice = make ([]int , 100000 ) for i := 0 ; i < 100000 ; i++ { newSlice = append (newSlice, i) } return newSlice }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package testimport "testing" func BenchmarkMakeSliceWithoutAlloc (b *testing.B) { for i := 0 ; i < b.N; i++ { MakeSliceWithoutAlloc() } } func BenchmarkMakeSliceWithAlloc (b *testing.B) { for i := 0 ; i < b.N; i++ { MakeSliceWithAlloc() } }
示例测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 package testimport "fmt" func SayHello () { fmt.Println("Hello!" ) } func SayGoodBye () { fmt.Println("Hello!" ) fmt.Println("GoodBye!" ) } func PrintNames () { names := make (map [int ]string , 4 ) names[1 ] = "Jim" names[2 ] = "Bob" names[3 ] = "Tom" names[4 ] = "Sue" for _, name := range names { fmt.Println(name) } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package testfunc ExampleSayHello () { SayHello() } func ExampleSayGoodBye () { SayGoodBye() } func ExamplePrintNames () { PrintNames() }
子测试 普通子测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package testimport "testing" func sub1 (t *testing.T) { var a = 1 var b = 2 var c = 3 r := Add(a, b) if c != r { t.Error("test Add fail" ) } } func sub2 (t *testing.T) { var a = 1 var b = 2 var c = 3 r := Add(a, b) if c != r { t.Error("test Add fail" ) } } func sub3 (t *testing.T) { var a = 1 var b = 2 var c = 3 r := Add(a, b) if c != r { t.Error("test Add fail" ) } } func TestSub (t *testing.T) { t.Run("sub1" , sub1) t.Run("sub2" , sub2) t.Run("sub3" , sub3) }
并发子测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package testimport ( "testing" "time" ) func parallelTest1 (t *testing.T) { t.Parallel() time.Sleep(3 * time.Second) } func parallelTest2 (t *testing.T) { t.Parallel() time.Sleep(2 * time.Second) } func parallelTest3 (t *testing.T) { t.Parallel() time.Sleep(1 * time.Second) } func TestSubParallel (t *testing.T) { t.Run("group" , func (t *testing.T) { t.Run("Test1" , parallelTest1) t.Run("Test2" , parallelTest2) t.Run("Test3" , parallelTest3) }) }